compute_score_in_validate <- function(exprs, model_coef = NULL) {
    suppressMessages(library(tidyverse))
    suppressMessages(library(magrittr))
    exprs <- exprs[model_coef[[1]], , drop = F] %>%
        t() %>%
        as.data.frame()

    miss_gene <- model_coef[, 1][which(is.na(exprs[1, ]))]
    miss_gene_symbol <- paste0(miss_gene, collapse = ", ")

    exprs[is.na(exprs)] <- 0

    riskscore_res <- as.matrix(exprs) %*% as.matrix(model_coef[, 2, drop = F]) %>%
        as.data.frame() %>%
        dplyr::rename(riskscore = 1)

    if (length(miss_gene) == 1) {
        cli::cli_alert_info(str_glue("'WARNING:' {miss_gene_symbol} 在当前队列的表达谱中没有匹配到。\n"))
    }

    return(riskscore_res)
}

#' @title 根据就不同方法计算得分
#' @description 根据输入建模方式或者自定义建模方式，来进行计算得分,也可以自定义function调用exprs、x或者其他参数计算得分。
#' @param model 字符串，已有的建模方法lasso,multicox,PCA1,PCA2。可以选择其中一个进行分析，也可以自定义
#' @param coef_df 根据model中不同的方式，给到不同的东西，比如说lasso方法需要给到基因coef相关的data.frame
#' @param exprs 表达谱
#' @param ... 可以自定义建模方法。把`exprs`与`coef_df`或者自定义的其他参数，传递到自定义函数内部的function，计算riskscore。自定义函数可以是匿名函数
#' 或者直接给一个riskscore，格式有要求：样本在行名，且只有一列，第一列表头为riskscore，内容为各个样本的得分。
#' @return 只有一列的data.frame，行名为样本名称，列名为riskscore
#' @usage
#' get_score_in_diff_model(
#'     model = "PCA1_minus_PCA2", coef_df = data.frame(
#'         gene = sample(rownames(TCGA$tumor_exprs), 12),
#'         HR = a
#'     ), exprs = TCGA$tumor_exprs
#' )() 
#' @export
#' @author *WYK*
#'
get_score_in_diff_model <- function(model, coef_df, exprs, ...) {
    if (!{
        model %in% c("lasso", "multi_cox", "PCA1_minus_PCA2", "PCA1_sum_PCA2")
    }) {
        lst_inner <- list(...)
        for (i in names(lst_inner)) {
            if (i != "") {
                assign(i, lst_inner[[i]])
            }
        }
        fun_defined <- \(...){}

        body(fun_defined) <- body(lst_inner[[which(map_lgl(lst_inner, ~ is.function(.x)))]])

        return(fun_defined)
    }

    coef_1_df <- data.frame(gene = "riskscore", coef = 1)

    model_inner <- list(
        lasso = \(...){
            if (!is.data.frame(coef_df)) {
                cli::cli_alert_danger(str_glue("{model}要求输入x是DF，且第一列为基因名，第二列为相关系数"))
                return()
            }
            score_res <- compute_score_in_validate(exprs, model_coef = coef_df)
            return(score_res)
        },
        multi_cox = \(...){
            if (!is.data.frame(coef_df)) {
                cli::cli_alert_danger(str_glue("{model}要求输入x是DF，且第一列为基因名，第二列为相关系数"))
                return()
            }
            score_res <- compute_score_in_validate(exprs, model_coef = coef_df)
            return(score_res)
        },
        PCA1_minus_PCA2 = \(...) {
            if (!any(grepl(pattern = "gene", x = colnames(coef_df)))) {
                cli::cli_alert_danger("coef_df中不存在{.var gene}列")
            }
            if (!any(grepl(pattern = "HR", x = colnames(coef_df)))) {
                cli::cli_alert_danger("coef_df中不存在{.var HR}列")
            }

            up_gene <- coef_df %>%
                filter(HR > 1) %>%
                pull(gene)
            down_gene <- coef_df %>%
                filter(HR < 1) %>%
                pull(gene)

            x_lst <- vector("list", 2)
            pacman::p_load(FactoMineR)

            x_lst[[1]] <- intersect(up_gene, rownames(exprs))
            x_lst[[2]] <- intersect(down_gene, rownames(exprs))

            if (length(x_lst[[1]]) <= 2 || length(x_lst[[2]]) <= 2 ) {
                cli::cli_alert_danger("在方法{.var PCA1_minus_PCA2}中，输入的基因列表的第一个或第二个元素在表达谱中交集小于2个，程序跳出。")
                return()
            }

            pcaH <- PCA(X = exprs[x_lst[[1]], ] %>% t(), graph = FALSE, ncp = 2)
            pcaL <- PCA(X = exprs[x_lst[[2]], ] %>% t(), graph = FALSE, ncp = 2)
            score <- pcaH$ind$contrib[, 1] + pcaH$ind$contrib[, 2] - pcaL$ind$contrib[, 1] - pcaL$ind$contrib[, 2]
            pca_res <- data.frame(PC1PC2 = score) %>% t()

            rownames(pca_res) <- 'riskscore'

            score_res <- compute_score_in_validate(exprs = pca_res, coef_1_df)
            return(score_res)
        },
        PCA1_sum_PCA2 = \(...) {
            if (!any(grepl(pattern = "gene", x = colnames(coef_df)))) {
                cli::cli_alert_danger("单因素cox结果中不存在{.var gene}列")
                return()
            }

            x <- coef_df$gene

            x <- intersect(x, rownames(exprs))
            pca_res <- prcomp(x = exprs[x, ], retx = F, scale = T, center = F)

            # print(">>>>>")
            pca_res <- pca_res$rotation %>%
                as.data.frame() %>%
                transmute(PC1PC2 = PC1 + PC2) %>%
                rename(riskscore = 1) %>%
                t() %>%
                as.data.frame()

            score_res <- compute_score_in_validate(exprs = pca_res, coef_1_df)
            return(score_res)
        }
    )

    return(model_inner[[model]])
}

# 测试部分
if (F) {
    TCGA <- readRDS("/Pub/Users/wangyk/project/p/F230113001_NSCLC/data/TCGA.rds")
    df <- read.delim("/Pub/Users/wangyk/project/p/F230113001_NSCLC/out/2.model/tcga/coef_df.tsv")

    get_score_in_diff_model(
        model = "PCA1_minus_PCA2",
        coef_df = data.frame(
            gene = sample(rownames(TCGA$tumor_exprs), 12),
            HR = a
        ), 
        exprs = TCGA$tumor_exprs
    )()
}
